package com.gmrz.uaf.protocol.v1.processor;

import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.db.DAOException;
import com.gmrz.uaf.db.UAFDAOFactory;
import com.gmrz.uaf.db.UAFDBConnectionMgr;
import com.gmrz.uaf.db.dao.AuthenticatorDAO;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.schema.*;
import com.gmrz.uaf.server.ServerConfig;
import com.gmrz.uaf.servlet.v1.request.GetUserInfoContextExt;
import com.gmrz.util.Convert;
import com.gmrz.util.CryUtil;
import com.gmrz.util.db.DBUtil;
import com.google.gson.Gson;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UAFUserInfoProcessor extends UAFBaseProcessor {
    private static final Logger LOG = LogManager.getLogger(UAFUserInfoProcessor.class);

    public List<UserInfoBean> getUserInfo(String hashedUserName, String appID, String deviceID, List<String> authType, List<String> transType, GetUserInfoContextExt ext) throws SQLException, DAOException {
        Connection conn = null;
        try {
            conn = UAFDBConnectionMgr.getConnection();
            AuthenticatorDAO dao = UAFDAOFactory.createAuthenticatorDAO(conn);
            List<UserInfoBean> userInfoBeans = dao.findUser(hashedUserName, appID, deviceID, authType, transType);
            for(String authTypeString : authType) {
                if ((authTypeString.compareTo(Constants.AuthType.CERT_FINGERPRINT.getAuthType()) >= 0) || (authTypeString.compareTo(Constants.AuthType.REMOTE_FACEPRINT.getAuthType()) < 0)) {
                    for(String t : transType) {
                        String applicationID = this.getServerConfig().getApplicationID(appID, t);
                        if (this.getServerConfig().getTenantShare() && com.gmrz.util.Strings.isNotBlank(applicationID)) {
                            List<String> shareAppIDList = getShareAppID(applicationID,t);
                            if (null != shareAppIDList && !shareAppIDList.isEmpty()) {
                                shareAppIDList.remove(appID);
                                for (String shareAppID : shareAppIDList) {
                                    List<UserInfoBean> shareUserInfoBeans = dao.findUser(hashedUserName, shareAppID, deviceID, Collections.singletonList(authTypeString), transType);
                                    userInfoBeans.addAll(shareUserInfoBeans);
                                }
                            }
                        }
                    }
                }
            }


            if (null != userInfoBeans && !userInfoBeans.isEmpty()) {
                for (UserInfoBean userInfoBean : userInfoBeans) {
                    userInfoBean.setAppId(this.getServerConfig().getApplicationID(appID,userInfoBean.getTransType()));
                    if(null != ext && "01".equals(ext.getNeedCert())){
                        byte[] challenge = getRandom(32);
                        CertificateBean certificateBean = dao.findCertByAuthId(userInfoBean.getAuthId());
                        if(null != certificateBean){
                            Gson gson = UAFSchemaBuilder.getGson();
                            byte[] key = new byte[16];
                            byte[] byte256 = CryUtil.getSHA256(challenge);
                            System.arraycopy(byte256,0,key,0,16);
                            byte[] certNoBytes = CryUtil.Aes256Encode(String.valueOf(certificateBean.getRegCounter()).getBytes(),key);
                            ExtBean extBean = new ExtBean();
                            extBean.setCertNo(Convert.toBase64(certNoBytes));
                            extBean.setCertPem(certificateBean.getCertText());
                            Extension extension = new Extension();
                            extension.setId("cert");
                            extension.setData(Convert.toBase64(gson.toJson(extBean).getBytes()));
                            userInfoBean.setExts(Collections.singletonList(extension));
                            userInfoBean.setChallenge(Convert.toBase64(challenge));
                        }
                    }
                }
            }
            return userInfoBeans;
        }catch (SQLException sqle){
            LOG.error("getUserInfo error",sqle);
            throw sqle;
        }catch (DAOException daoe){
            LOG.error("getUserInfo error",daoe);
            throw daoe;
        }catch (Exception e){
            LOG.error("getUserInfo error",e);
        } finally{
            DBUtil.close(conn);
        }
        return null;
    }

    public List<UserInfoBean> getUserInfoAllCert(String hashedUserName, String appID, String deviceID,String custNO) throws SQLException, DAOException {
        Connection conn = null;
        try {
            List<String> authType = new ArrayList<String>();
            for(Constants.AuthType auth: Constants.AuthType.values()) {
                if(auth.getAuthType().compareTo(Constants.AuthType.CERT_FINGERPRINT.getAuthType()) >= 0) {
                    authType.add(auth.getAuthType());
                }
            }

            List<String> transType = new ArrayList<String>();
            transType.add("00");
            transType.add("01");
            transType.add("02");
            conn = UAFDBConnectionMgr.getConnection();
            AuthenticatorDAO dao = UAFDAOFactory.createAuthenticatorDAO(conn);
            List<UserInfoBean> userInfoBeans = dao.findUser(hashedUserName, appID, deviceID, authType, transType);
            for(String authTypeString : authType) {
                if ((authTypeString.compareTo(Constants.AuthType.CERT_FINGERPRINT.getAuthType()) >= 0) || (authTypeString.compareTo(Constants.AuthType.REMOTE_FACEPRINT.getAuthType()) < 0)) {
                    for(String t : transType) {
                        String applicationID = this.getServerConfig().getApplicationID(appID, t);
                        if (this.getServerConfig().getTenantShare() && com.gmrz.util.Strings.isNotBlank(applicationID)) {
                            List<String> shareAppIDList = getShareAppID(applicationID,t);
                            if (null != shareAppIDList && !shareAppIDList.isEmpty()) {
                                shareAppIDList.remove(appID);
                                for (String shareAppID : shareAppIDList) {
                                    List<UserInfoBean> shareUserInfoBeans = dao.findUser(hashedUserName, shareAppID, deviceID, Collections.singletonList(authTypeString), transType);
                                    userInfoBeans.addAll(shareUserInfoBeans);
                                }
                            }
                        }
                    }
                }
            }


            if (null != userInfoBeans && !userInfoBeans.isEmpty()) {
                for (UserInfoBean userInfoBean : userInfoBeans) {
                    userInfoBean.setAppId(this.getServerConfig().getApplicationID(appID,userInfoBean.getTransType()));
                    if (!GuiceUtil.getProcessorInjector().getInstance(ServerConfig.class).isSecurity()) {
                        userInfoBean.setUserName(userInfoBean.getCustNo());
                    }else {
                        String userName = userInfoBean.getUserName();
                        String aType = userInfoBean.getAuthType();
                        String tType = userInfoBean.getTransType();
                        userInfoBean.setUserName( userName+ "_" + aType + "_" + tType);
                    }
                }
            }else {
                if(null == userInfoBeans){
                    userInfoBeans = new ArrayList<UserInfoBean>();
                }
                for(String tType : transType) {
                    UserInfoBean userInfoBean = new UserInfoBean();
                    userInfoBean.setAppId(this.getServerConfig().getApplicationID(appID, tType));
                    userInfoBean.setTenantId(appID);
                    if (!GuiceUtil.getProcessorInjector().getInstance(ServerConfig.class).isSecurity()) {
                        userInfoBean.setUserName(custNO);
                    }else {
                        String userName = hashedUserName;
                        String aType = "20";
                        userInfoBean.setUserName( userName+ "_" + aType + "_" + tType);
                    }
                    userInfoBeans.add(userInfoBean);
                }
            }
            return userInfoBeans;
        }catch (SQLException sqle){
            LOG.error("getUserInfo error",sqle);
            throw sqle;
        }catch (DAOException daoe){
            LOG.error("getUserInfo error",daoe);
            throw daoe;
        }catch (Exception e){
            LOG.error("getUserInfo error",e);
        } finally{
            DBUtil.close(conn);
        }
        return null;
    }
}
